package com.icloud.wallet.boot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.icloud.common.core.api.ResultCode;
import com.icloud.common.database.enums.*;
import com.icloud.common.database.mapper.*;
import com.icloud.common.database.model.*;
import com.icloud.common.web.enums.StateEnum;
import com.icloud.common.web.exception.Asserts;
import com.icloud.wallet.api.dto.CustomerHotArticleDto;
import com.icloud.wallet.api.dto.CustomerRewardDto;
import com.icloud.common.database.mapper.TWalletJournalMapper;
import com.icloud.common.database.model.TWalletJournal;
import com.icloud.wallet.boot.service.IArticleOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

@Slf4j
@Service
public class ArticleOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrders> implements IArticleOrderService {
    @Autowired
    private AppCustomerMapper appCustomerMapper;
    @Autowired
    private CustomerWalletMapper customerWalletMapper;
    @Autowired
    private TOrderMapper tOrderMapper;
    @Autowired
    private TRewardOrderItemMapper tRewardOrderItemMapper;
    @Autowired
    private THotArticleOrderItemMapper tHotArticleOrderItemMapper;
    @Autowired
    private TWalletJournalMapper tWalletJournalMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean reward(CustomerRewardDto dto) {
        LocalDateTime now = LocalDateTime.now();

        Long rewardId = dto.getCreatedId();
        AppCustomer rewarder = appCustomerMapper.selectById(rewardId);
        Asserts.fail(null==rewarder, ResultCode.DATA_NOT_EXISTS);

        Long authorId = dto.getAuthorId();
        AppCustomer author = appCustomerMapper.selectById(authorId);
        Asserts.fail(null==author, ResultCode.DATA_NOT_EXISTS);

        BigDecimal amount = dto.getAmount();

        LambdaQueryWrapper<CustomerWallet> rewarderWallQuer = new LambdaQueryWrapper<>();
        rewarderWallQuer.eq(CustomerWallet::getCustomerId, rewardId);
        CustomerWallet rewarderWallet = customerWalletMapper.selectOne(rewarderWallQuer);

        LambdaQueryWrapper<CustomerWallet> authorWallQuer = new LambdaQueryWrapper<>();
        authorWallQuer.eq(CustomerWallet::getCustomerId, authorId);
        CustomerWallet authorWallet = customerWalletMapper.selectOne(authorWallQuer);

        BigDecimal rewarderBeforeBalance = rewarderWallet.getBcpc();
        BigDecimal authorBeforeBalance = authorWallet.getBcpc();
        Asserts.fail(amount.compareTo(rewarderBeforeBalance)>0, ResultCode.INSUFFICIENT_BALANCE);

        Long rewardTime = dto.getRewardTime();
        LocalDateTime orderDate = now;
        if(rewardTime!=null) {
            orderDate = LocalDateTime.ofInstant(Instant.ofEpochSecond(rewardTime), ZoneId.systemDefault());
        }

        TOrders tOrders = TOrders.builder()
                .customerId(rewardId)
                .orderType(OrderTypeEnum.REWARD.getCode())
                .amount(amount)
                .orderTime(orderDate)
                .paymentTime(now)
                .paymentState(PaymentStateEnum.FINISHED.getCode())
                .state(StateEnum.NORMAL.getCode())
                .createdId(rewardId)
                .updatedId(rewardId)
                .build();
        tOrderMapper.insert(tOrders);

        Long orderId = tOrders.getId();

        TRewardOrderItem tRewardOrderItem = TRewardOrderItem.builder()
                .orderId(orderId)
                .articleId(dto.getArticleId())
                .authorId(authorId)
                .createdId(rewardId)
                .build();
        tRewardOrderItemMapper.insert(tRewardOrderItem);

        // 更新钱包余额
        BigDecimal rewarderAfterBalance = rewarderBeforeBalance.subtract(amount);
        BigDecimal authorAfterBalance = authorBeforeBalance.add(amount);

        // 打赏流水
        TWalletJournal rewardJournal = TWalletJournal.builder()
                .customerId(rewardId)
                .orderId(orderId)
                .journalType(JournalTypeEnum.REWARD.getCode())
                .beforeBalance(rewarderBeforeBalance)
                .amount(amount)
                .afterBalance(rewarderAfterBalance)
                .currency(CurrencyEnum.BCPC.getCode())
                .direction(DirectionEnum.CREDIT.getCode())
                .journalState(JournalStateEnum.FINISHED.getCode())
                .remark("支付打赏订单")
                .createdId(rewardId)
                .updatedId(rewardId)
                .build();
        tWalletJournalMapper.insert(rewardJournal);

        CustomerWallet updateRewarderWallet = CustomerWallet.builder()
                .id(rewarderWallet.getId())
                .bcpc(rewarderAfterBalance)
                .build();
        customerWalletMapper.updateById(updateRewarderWallet);

        // 接受打赏流水
        TWalletJournal getRewardJournal = TWalletJournal.builder()
                .customerId(authorId)
                .orderId(orderId)
                .journalType(JournalTypeEnum.GET_REWARD.getCode())
                .beforeBalance(authorBeforeBalance)
                .amount(amount)
                .afterBalance(authorAfterBalance)
                .currency(CurrencyEnum.BCPC.getCode())
                .direction(DirectionEnum.CREDIT.getCode())
                .journalState(JournalStateEnum.FINISHED.getCode())
                .remark("接受打赏订单")
                .createdId(authorId)
                .updatedId(authorId)
                .build();
        tWalletJournalMapper.insert(getRewardJournal);

        CustomerWallet updateAuthorWallet = CustomerWallet.builder()
                .id(authorWallet.getId())
                .bcpc(authorAfterBalance)
                .build();
        customerWalletMapper.updateById(updateAuthorWallet);

        return true;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean hotArticle(CustomerHotArticleDto dto) {
        LocalDateTime now = LocalDateTime.now();

        Long hotId = dto.getCreatedId();
        AppCustomer hoter = appCustomerMapper.selectById(hotId);
        Asserts.fail(null==hoter, ResultCode.DATA_NOT_EXISTS);

        Long authorId = dto.getAuthorId();
        AppCustomer author = appCustomerMapper.selectById(authorId);
        Asserts.fail(null==author, ResultCode.DATA_NOT_EXISTS);

        BigDecimal amount = dto.getAmount();

        LambdaQueryWrapper<CustomerWallet> hoterWallQuer = new LambdaQueryWrapper<>();
        hoterWallQuer.eq(CustomerWallet::getCustomerId, hotId);
        CustomerWallet hoterWallet = customerWalletMapper.selectOne(hoterWallQuer);

        BigDecimal hoterBeforeBalance = hoterWallet.getBcpc();
        Asserts.fail(amount.compareTo(hoterBeforeBalance)>0, ResultCode.INSUFFICIENT_BALANCE);

        Long hotTime = dto.getHotTime();
        LocalDateTime orderDate = now;
        if(hotTime!=null) {
            orderDate = LocalDateTime.ofInstant(Instant.ofEpochSecond(hotTime), ZoneId.systemDefault());
        }

        TOrders tOrders = TOrders.builder()
                .customerId(hotId)
                .orderType(OrderTypeEnum.HOT.getCode())
                .amount(amount)
                .orderTime(orderDate)
                .paymentTime(now)
                .paymentState(PaymentStateEnum.FINISHED.getCode())
                .state(StateEnum.NORMAL.getCode())
                .createdId(hotId)
                .updatedId(hotId)
                .build();
        tOrderMapper.insert(tOrders);

        Long orderId = tOrders.getId();

        THotArticleOrderItem tHotArticleOrderItem = THotArticleOrderItem.builder()
                .orderId(orderId)
                .articleId(dto.getArticleId())
                .authorId(authorId)
                .createdId(hotId)
                .duration(dto.getDuration())
                .build();
        tHotArticleOrderItemMapper.insert(tHotArticleOrderItem);

        // 更新钱包余额
        BigDecimal hoterAfterBalance = hoterBeforeBalance.subtract(amount);

        // 热帖流水
        TWalletJournal rewardJournal = TWalletJournal.builder()
                .customerId(hotId)
                .orderId(orderId)
                .journalType(JournalTypeEnum.HOT.getCode())
                .beforeBalance(hoterBeforeBalance)
                .amount(amount)
                .afterBalance(hoterAfterBalance)
                .currency(CurrencyEnum.BCPC.getCode())
                .direction(DirectionEnum.CREDIT.getCode())
                .journalState(JournalStateEnum.FINISHED.getCode())
                .remark("支付热帖订单")
                .createdId(hotId)
                .updatedId(hotId)
                .build();
        tWalletJournalMapper.insert(rewardJournal);

        CustomerWallet updateRewarderWallet = CustomerWallet.builder()
                .id(hoterWallet.getId())
                .bcpc(hoterAfterBalance)
                .build();
        customerWalletMapper.updateById(updateRewarderWallet);
        return false;
    }
}
